package com.rankeiot.platform.controller;


import cn.beecp.BeeDataSource;
import cn.beecp.BeeDataSourceConfig;
import cn.hutool.core.io.FileUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.CryptoUtils;
import com.rankeiot.core.EasyCorePlugin;
import com.rankeiot.core.data.response.Resp;
import com.rankeiot.platform.PlatformModule;
import com.rankeiot.platform.service.CacheDataService;
import com.rankeiot.platform.service.ConfigServiceImpl;
import com.rankeiot.platform.service.PlatformInstallListener;
//import com.zaxxer.hikari.HikariConfig;
//import com.zaxxer.hikari.HikariDataSource;
import lombok.RequiredArgsConstructor;
import lombok.Data;
import org.sagacity.sqltoy.SqlToyContext;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.sagacity.sqltoy.dao.impl.SqlToyLazyDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.Yaml;

import javax.sql.DataSource;
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;


/**
 * 系统安装,未检测到数据库配置的时候动态加载
 */
@RestController
@RequestMapping("install")
@RequiredArgsConstructor
public class InstallController {

    final CacheDataService cacheDataService;
    final ConfigServiceImpl configService;
    final ConfigurableApplicationContext context;


    final ConfigurableEnvironment env;
    final SqlToyLazyDao dao;

    @Autowired(required = false)
    private DynamicRoutingDataSource dynamicRoutingDataSource;

    @PostMapping("install")
    public Object install(@RequestBody InstallConfig config) {
        if (EasyCorePlugin.hasDataSource) {
            Resp.fail("安装错误");
        }
        PlatformInstallListener.PlatformInstallEvent event = new PlatformInstallListener.PlatformInstallEvent();
        event.setConfig(config);
        String jdbcUrl= config.getJdbcUrl();
        boolean isMysql=false;
        if("com.mysql.jdbc.Driver".equals(config.getDriver())){
           jdbcUrl = "jdbc:mysql://" + config.getIp() + ":" + config.getPort()//+"/"+config.getDbName()
                    + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true&rewriteBatchedStatements=true&useInformationSchema=true";
            isMysql=true;
        }
        //HikariConfig dc=new HikariConfig();
       BeeDataSourceConfig dc = new BeeDataSourceConfig();
        dc.setUsername(config.getUsername());
        dc.setPassword(config.getPassword());
        dc.setJdbcUrl(jdbcUrl);
        dc.setDriverClassName(config.getDriver());
        try {
            Class.forName(config.getDriver(),false,InstallController.class.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
           Resp.fail("没有找到JDBC驱动："+config.getDriver());
        }
        BeeDataSource ds = new BeeDataSource(dc);
       // DataSource ds=new DataS
       // HikariDataSource ds=new HikariDataSource(dc);
        try (Connection connection = ds.getConnection()) {
            //event.setConnection(connection);
            if(isMysql){
                ResultSet resultSet = connection.getMetaData().getCatalogs();
                boolean hasDb = false;
                while (resultSet.next()) {
                    String databaseName = resultSet.getString(1);
                    if (Objects.equals(databaseName, config.getDbName())) {
                        hasDb = true;
                        break;
                    }
                }
                if (!hasDb) {
                    Statement stmt = connection.createStatement();
                    String sql = "CREATE DATABASE " + config.dbName +" DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci";
                    stmt.executeUpdate(sql);
                    stmt.close();
                }
                jdbcUrl = "jdbc:mysql://" + config.getIp() + ":" + config.getPort() + "/" + config.getDbName()
                        + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true&rewriteBatchedStatements=true&useInformationSchema=true";
            }

            //初始化数据库
            if (config.installType == 1) {
                dc = new BeeDataSourceConfig();//new HikariConfig();
                dc.setUsername(config.getUsername());
                dc.setPassword(config.getPassword());
                dc.setJdbcUrl(jdbcUrl);
                BeeDataSource newDs = new BeeDataSource(dc);
                try (Connection conn = newDs.getConnection()) {
                    event.setConnection(conn);
                    conn.setAutoCommit(false);
                    //EventBus.push(event);
                    context.publishEvent(event);
                    conn.commit();
                } catch (SQLException e) {
                    e.printStackTrace();
                    Resp.fail("数据库初始化失败:" + e.getMessage());
                }
                newDs.close();
            }
            //配置连接
//            HikariDataSource platformDs = (HikariDataSource)context.getBean(DataSource.class);//(BeeDataSource) Solon.context().getBean(DataSource.class);
//            if(platformDs==null){
//                platformDs=new HikariDataSource();
//               // Solon.context().wrapAndPut(DataSource.class,platformDs);
//            }
//            platformDs.setUsername(config.getUsername());
//            platformDs.setPassword(config.getPassword());
//            platformDs.setJdbcUrl(jdbcUrl);

            //添加配置属性

            String dsc="spring:\n";
            dsc+=" datasource:\n";
            dsc+="  dynamic:\n";
            dsc+="   primary: master\n";
            dsc+="   datasource:\n";
            dsc+="    master:\n";
            dsc+="     url: "+jdbcUrl+"\n";
            dsc+="     username: "+enc(config.getUsername())+"\n";
            dsc+="     password: "+enc(config.getPassword())+"\n";

            dc.setJdbcUrl(jdbcUrl);
            BeeDataSource master = new BeeDataSource(dc);
            if(dynamicRoutingDataSource==null){
                dynamicRoutingDataSource=new DynamicRoutingDataSource();
                BeanDefinitionRegistry beanDefinitionRegistry=(BeanDefinitionRegistry)context.getBeanFactory();
                beanDefinitionRegistry.registerBeanDefinition("com.baomidou.dynamic.datasource.DynamicRoutingDataSource", BeanDefinitionBuilder.genericBeanDefinition(DynamicRoutingDataSource.class,()->dynamicRoutingDataSource).getBeanDefinition());
                ((SqlToyLazyDaoImpl)dao).setDataSource(dynamicRoutingDataSource);
                dao.getSqlToyContext().setDefaultDataSource(dynamicRoutingDataSource);
            }

            dynamicRoutingDataSource.setPrimary("master");
            dynamicRoutingDataSource.addDataSource("master",master);

            EasyCorePlugin.hasDataSource = true;

            cacheDataService.init();
            configService.init();

            String suffix=env.getProperty("spring.profiles.active");
            if(suffix!=null){
                suffix="-"+suffix;
            }else{
                suffix="";
            }
            //保存配置
            File appYml = new File("./application"+suffix+".yml");

            Yaml yaml = new Yaml();
//            Map<String, Object> data = new LinkedHashMap<>();
//            if (appYml.exists()) {
//                try (InputStream ai = new FileInputStream(appYml)) {
//                    data = yaml.load(ai);
//                    if(data==null){
//                        data=new LinkedHashMap<>();
//                    }
//                } catch (FileNotFoundException e) {
//                    throw new RuntimeException(e);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            }
            //设置验证密码,如果没有配置，就用serverId作为密码
//            String vaultPwd = Solon.cfg().get("solon.vault.password");
//            if (StringUtil.isEmpty(vaultPwd)) {
//                Solon.cfg().setProperty("solon.vault.password", PlatformModule.serverId);
//                Solon.context().wrapAndPut(VaultCoder.class, new AesVaultCoder());
//                data.put("solon.vault.password", PlatformModule.serverId);
//            }
//            String encPassword="";
          //  String encPassword = VaultUtils.encrypt(config.getPassword());//new AesVaultCoder().encrypt(config.password);
//            Map<String, Object> dbConfig = new LinkedHashMap<>();
//            dbConfig.put("username", config.getUsername());
//            dbConfig.put("password", encPassword);
//            dbConfig.put("url", jdbcUrl);
//            data.put("master", dbConfig);

            // data.put("solon.app.name",config.getAppName());

            FileUtil.writeUtf8String(dsc, appYml);

//            Router router = Solon.app().router();
//            router.remove("/install");

        } catch (SQLException e) {
            e.printStackTrace();
            String message = null;
            if (e.getCause() != null) {
                message = e.getCause().getLocalizedMessage();
            } else {
                message = e.getLocalizedMessage();
            }
            Resp.fail("数据库连接失败:" + message);
        } catch (Exception e) {
           e.printStackTrace();
           Resp.fail(e.getMessage());
        } finally {
            ds.close();
        }
        return Resp.ok("初始化完成");
    }
    //加密数据
    private String enc(String pwd){
        try {
            return "ENC("+ CryptoUtils.encrypt(pwd)+")";
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Data
    public static class InstallConfig {
        private int installType;
        private String dbName;
        private String ip;
        private int port;
        private String username;
        private String password;
        private String appName;
        private String jdbcUrl;
        private String driver;
    }
}
